﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Tile_Engine;

namespace AGrandVenture
{
    public class Player : GameObject
    {
        #region CharacterReference
        private static PlayerCharacter character;
        #endregion

        #region SpriteDeclarations
        public static Sprite BaseSprite;
        public static Sprite TurretSprite;

        public static Vector2 WorldLocation = Vector2.Zero;

        private static Vector2 baseAngle = Vector2.Zero;
        private static Vector2 turretAngle = Vector2.Zero;
        private static float playerSpeed = 180f;
        

        private static Rectangle scrollArea = new Rectangle(150, 100, (1130 - 128) - 256, 620 - 128); //defines a rectangle that will scroll the camera when the sprite hits the rectangle bounds
        #endregion

        #region Properties

        public static Vector2 MoveAngle
        {
            get { return baseAngle; }
        }

        public static Vector2 PathingNodePosition
        {
            get
            {
                return TileMap.GetCellByPixel(BaseSprite.WorldCentre);
            }
        }

        public static PlayerCharacter Character
        {
            get;
            set;
        }

        public static MeleeAttack MeleeAtk
        {
            get;
            set;
        }
        #endregion

        #region Initalisation
        public static void Initialise(Texture2D texture, Rectangle baseInitialFrame, int baseFrameCount, Rectangle turretInitialFrame, int turretFrameCount, Vector2 worldLocation)
        {
            int frameWidth = baseInitialFrame.Width;
            int frameHeight = baseInitialFrame.Height;

            BaseSprite = new Sprite(worldLocation, texture, baseInitialFrame, Vector2.Zero, 0.85f);
            BaseSprite.BoundingXPadding = 4;
            BaseSprite.BoundingYPadding = 4;
            BaseSprite.AnimateWhenStopped = false;
            BaseSprite.spriteScale = 1f;
            BaseSprite.Animate = false;

            for (int x = 1; x < baseFrameCount; x++)
            {
                BaseSprite.AddFrame(
                    new Rectangle(
                        baseInitialFrame.X + (frameHeight * x),
                        baseInitialFrame.Y,
                        frameWidth,
                        frameHeight));
            }

            TurretSprite = new Sprite(worldLocation, texture, turretInitialFrame, Vector2.Zero, 0.85f);

           
            TurretSprite.Animate = false;
            TurretSprite.spriteScale = 1f;

            for (int x = 1; x < turretFrameCount; x++)
            {
                BaseSprite.AddFrame(
                    new Rectangle(
                        turretInitialFrame.X + (frameHeight * x),
                        turretInitialFrame.Y,
                        frameWidth,
                        frameHeight));
            }

            WorldLocation = BaseSprite.WorldLocation;
            character = new PlayerCharacter("Player Name", PlayerCharacter.ClassType.Gladiator, PlayerCharacter.RaceType.Human);
            Character = character;
        }
        #endregion

        #region Update and Draw
        public static void Update(GameTime gameTime)
        {
            handleInput(gameTime);
            BaseSprite.Update(gameTime);
            clampToWorld();
            TurretSprite.WorldLocation = BaseSprite.WorldLocation;
            WorldLocation = BaseSprite.WorldLocation;

            if (MeleeAtk != null)
                MeleeAtk.Update(gameTime);
        }

        public static void Draw(SpriteBatch spriteBatch)
        {
            TurretSprite.Draw(spriteBatch);
            BaseSprite.Draw(spriteBatch);
            if (MeleeAtk != null)
                MeleeAtk.Draw(spriteBatch);

        }
        #endregion

        #region Input Handling
        private static Vector2 handleKeyBoardMovement(KeyboardState keyState)
        {
            Vector2 keyMovement = Vector2.Zero;
            if (keyState.IsKeyDown(Keys.W))
                keyMovement.Y--;

            if (keyState.IsKeyDown(Keys.A))
                keyMovement.X--;

            if (keyState.IsKeyDown(Keys.S))
                keyMovement.Y++;

            if (keyState.IsKeyDown(Keys.D))
                keyMovement.X++;

            return keyMovement;
        }

        private static Vector2 handleGamePadMovement(GamePadState gamepadState)
        {
            return new Vector2(gamepadState.ThumbSticks.Left.X, -gamepadState.ThumbSticks.Left.Y);
        }

        private static Vector2 handleKeyBoardShots(KeyboardState keyState)
        {
            Vector2 keyShots = Vector2.Zero;

            if (keyState.IsKeyDown(Keys.NumPad1))
                keyShots = new Vector2(-1, 1);

            if (keyState.IsKeyDown(Keys.NumPad2))
                keyShots = new Vector2(0, 1);

            if (keyState.IsKeyDown(Keys.NumPad3))
                keyShots = new Vector2(1, 1);

            if (keyState.IsKeyDown(Keys.NumPad4))
                keyShots = new Vector2(-1, 0);

            if (keyState.IsKeyDown(Keys.NumPad6))
                keyShots = new Vector2(1, 0);

            if (keyState.IsKeyDown(Keys.NumPad7))
                keyShots = new Vector2(-1, -1);

            if (keyState.IsKeyDown(Keys.NumPad8))
                keyShots = new Vector2(0, -1);

            if (keyState.IsKeyDown(Keys.NumPad9))
                keyShots = new Vector2(1, -1);

            return keyShots;
        }

        private static Vector2 handleGamePadShots(GamePadState gamepadState)
        {
            return new Vector2(gamepadState.ThumbSticks.Right.X, -gamepadState.ThumbSticks.Right.Y);
        }

        private static void handleInput(GameTime gameTime)
        {
            float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;

            Vector2 moveAngle = Vector2.Zero;
            Vector2 fireAngle = Vector2.Zero;

            moveAngle += handleKeyBoardMovement(Keyboard.GetState());
            moveAngle += handleGamePadMovement(GamePad.GetState(PlayerIndex.One));

            fireAngle += handleKeyBoardShots(Keyboard.GetState());
            fireAngle += handleGamePadShots(GamePad.GetState(PlayerIndex.One));

            if (moveAngle != Vector2.Zero)
            {
                moveAngle.Normalize();
                baseAngle = moveAngle;
                moveAngle = checkTileObstables(elapsed, moveAngle);
            }

            if (fireAngle != Vector2.Zero)
            {
                fireAngle.Normalize();
                turretAngle = fireAngle;

                if (WeaponManager.CanFireWeapon)
                {
                    WeaponManager.FireWeapon(TurretSprite.WorldLocation, fireAngle * WeaponManager.WeaponSpeed);
                    
                }
            }

           
            BaseSprite.RotateTo(baseAngle);
            TurretSprite.RotateTo(turretAngle);

            //Handle Melee Attack
            if (InputHandler.ButtonPressed(Buttons.X,PlayerIndex.One) || InputHandler.KeyPressed(Keys.X))
            {
                Vector2 attackLocation = Player.WorldLocation;
                if (moveAngle.X > 0)
                    attackLocation.X += 48;
                if (moveAngle.Y > 0)
                    attackLocation.Y += 48;

                MeleeAtk = new MeleeAttack(20, 50, attackLocation);
            }

            BaseSprite.Velocity = moveAngle * playerSpeed;
            repositionCamera(gameTime, moveAngle);
        }
        #endregion

        #region Movement Limitations

        private static void clampToWorld()
        {
            float currentX = BaseSprite.WorldLocation.X;
            float currentY = BaseSprite.WorldLocation.Y;

            currentX = MathHelper.Clamp(
                currentX,
                0,
                Camera.WorldRectangle.Right - BaseSprite.FrameWidth);

            currentY = MathHelper.Clamp(
                currentY,
                0,
                Camera.WorldRectangle.Bottom - BaseSprite.FrameHeight);

            BaseSprite.WorldLocation = new Vector2(currentX, currentY);
        }

        private static void repositionCamera(GameTime gameTime, Vector2 moveAngle)
        {
            float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;
            float moveScale = playerSpeed * elapsed;

            if ((BaseSprite.ScreenRectangle.X < scrollArea.X) && (moveAngle.X < 0))
            {
                Camera.Move(new Vector2(moveAngle.X, 0) * moveScale);
            }

            if ((BaseSprite.ScreenRectangle.Right > scrollArea.Right) && (moveAngle.X > 0))
            {
                Camera.Move(new Vector2(moveAngle.X, 0) * moveScale);
            }

            if ((BaseSprite.ScreenRectangle.Y < scrollArea.Y) && (moveAngle.Y < 0))
            {
                Camera.Move(new Vector2(0, moveAngle.Y) * moveScale);
            }

            if ((BaseSprite.ScreenRectangle.Bottom > scrollArea.Bottom) && (moveAngle.Y > 0))
            {
                Camera.Move(new Vector2(0, moveAngle.Y) * moveScale);
            }

        }

        private static Vector2 checkTileObstables(float elapsedTime, Vector2 moveAngle)
        {
            Vector2 newHorizontalLocation = BaseSprite.WorldLocation + (new Vector2(moveAngle.X, 0) * (playerSpeed * elapsedTime));
            Vector2 newVerticalLocation = BaseSprite.WorldLocation + (new Vector2(0, moveAngle.Y) * (playerSpeed * elapsedTime));

            Rectangle newHorizontalRect = new Rectangle(
                (int)newHorizontalLocation.X,
                (int)BaseSprite.WorldLocation.Y,
                BaseSprite.FrameWidth,
                BaseSprite.FrameHeight);

            Rectangle newVerticalRect = new Rectangle(
                (int)BaseSprite.WorldLocation.X,
                (int)newVerticalLocation.Y,
                BaseSprite.FrameWidth,
                BaseSprite.FrameHeight);

            int horizLeftPixel = 0;
            int horizRightPixel = 0;

            int vertTopPixel = 0;
            int vertBottomPixel = 0;

            if (moveAngle.X < 0)
            {
                horizLeftPixel = (int)newHorizontalRect.Left;
                horizRightPixel = (int)BaseSprite.WorldRectangle.Left;
            }

            if (moveAngle.X > 0)
            {
                horizLeftPixel = (int)BaseSprite.WorldRectangle.Right;
                horizRightPixel = (int)newHorizontalRect.Right;
            }

            if (moveAngle.Y < 0)
            {
                vertTopPixel = (int)newVerticalRect.Top;
                vertBottomPixel = (int)BaseSprite.WorldRectangle.Top;
            }

            if (moveAngle.Y > 0)
            {
                vertTopPixel = (int)BaseSprite.WorldRectangle.Bottom;
                vertBottomPixel = (int)newVerticalRect.Bottom;
            }

            if (moveAngle.X != 0)
            {
                for (int x = horizLeftPixel; x < horizRightPixel; x++)
                {
                    for (int y = 0 + BaseSprite.BoundingYPadding; y < BaseSprite.FrameHeight - BaseSprite.BoundingYPadding; y++)
                    {

                        Vector2 mapcell1 = TileMap.GetCellByPixel(new Vector2(x, newHorizontalLocation.Y + y));

                        if (!TileMap.CellIsPassable(mapcell1))
                        {
                            moveAngle.X = 0;
                            break;
                        }
                    }
                    if (moveAngle.X == 0)
                    {
                        break;
                    }
                }
            }

            if (moveAngle.Y != 0)
            {
                for (int y = vertTopPixel; y < vertBottomPixel; y++)
                {
                    for (int x = 0 + BaseSprite.BoundingXPadding; x < BaseSprite.FrameWidth - BaseSprite.BoundingXPadding; x++)
                    {

                        Vector2 mapcell2 = TileMap.GetCellByPixel(new Vector2(newVerticalLocation.X + x, y));

                        if (!TileMap.CellIsPassable(mapcell2))
                        {
                            moveAngle.Y = 0;
                            break;
                        }
                    }
                    if (moveAngle.Y == 0)
                    {
                        break;
                    }
                }
            }
            return moveAngle;
        }


        #endregion

        #region Public Methods

        #endregion
    }
}
